<template>
  <div>
  <div style="height: 40px;">
    <div style="float: left">
    <el-upload  action class="upload-demo" :before-upload="openBpmn">
      <el-button type="primary" size="mini" icon="el-icon-folder-opened">打开</el-button>
    </el-upload>
    </div>
    <div style="float: left;padding-left: 10px">
      <el-button-group>
      <a hidden ref="downloadLink"></a>
      <el-button type="primary"  @click="createBpmn" size="mini" icon="el-icon-circle-plus-outline">新建</el-button>
      <el-button type="primary" size="mini" @click="saveFlow(1)" icon="el-icon-save">保存并发布</el-button>
      <el-button type="primary" size="mini"  @click="saveFlow(0)" icon="el-icon-save">保存到草稿</el-button>
      <el-button type="primary" @click="downloadSvg" size="mini" icon="el-icon-picture-outline">导出SVG</el-button>
      <el-button type="primary" @click="downloadBpmn" size="mini" icon="el-icon-download">导出BPMN</el-button>
      </el-button-group>
    </div>
   </div>
  <div class="containers" style="height:700px;width:1300px;border: #ababab solid 1px;">
    <el-row>
      <el-col :span="18">
        <div class="canvas" ref="canvas" />
      </el-col>
      <el-col :span="6" >
        <panel v-if="bpmnModeler" :modeler="bpmnModeler" />
      </el-col>
    </el-row>

  </div>
  </div>
</template>

<script>
import { saveData, fetchDetail } from '@/api/flowable/flowable'
import BpmnModeler from 'bpmn-js/lib/Modeler' // bpmn-js 设计器
import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/bpmn' // bpmn-js 设计器
import panel from './PropertyPanel' // 属性面板

export default {
  name: 'VueBpmn',
  props: {
    flowId: {
      type: String,
      default: () => {
        return 'process_' + Math.random()
      }
    }
  },
  data() {
    return {
      id: '',
      bpmnModeler: null,
      element: null,
      rangeValue: 1.0,
      bpmnTemplate: `<?xml version="1.0" encoding="UTF-8"?>
            <bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:flowable="http://flowable.org/bpmn" id="sample-diagram" targetNamespace="http://www.activiti.org/processdef" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
                <bpmn2:process  id="` + 'process_' + this.getRandom(10) + `" name="新建流程" >
                <bpmn2:startEvent id="StartEvent_1668944740266" name="开始" activit:formType="1" activit:initiator="applyUserId">
                <bpmn2:extensionElements />
              </bpmn2:startEvent>
            </bpmn2:process>
              <bpmndi:BPMNDiagram id="BPMNDiagram_1">
                <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1668944683443">
                  <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1668944740266">
                    <dc:Bounds x="209" y="283" width="36" height="36" />
                    <bpmndi:BPMNLabel>
                      <dc:Bounds x="217" y="326" width="22" height="14" />
                    </bpmndi:BPMNLabel>
                  </bpmndi:BPMNShape>
                </bpmndi:BPMNPlane>
              </bpmndi:BPMNDiagram>
            </bpmn2:definitions>`
    }
  },
  components: {
    panel
  },
  watch: {
    flowId: {
      handler() {
        this.id = this.flowId
        if (this.flowId) {
          this.id = this.flowId
          this.fetchData(this.flowId)
        } else {
          this.id = this.getRandom(19)
          this.createNewDiagram(this.bpmnTemplate)
        }
      }
    }
  },
  created() {
  },
  methods: {
    async createNewDiagram(xml) {
      try {
        // 将字符串转换成图显示出来
        await this.bpmnModeler.importXML(xml, err => {
          if (err) {
            console.error(err)
          } else {
            this.adjustPalette()
          }
        })
      } catch (err) {
        console.log(err.message, err.warnings)
      }
    },
    createBpmn() {
      this.createNewDiagram(this.bpmnTemplate)
    },
    fetchData(id) {
      fetchDetail(id).then(response => {
        console.info(response)
        this.bpmnTemplate = response.data.thumbnail
        this.id = response.data.id
        this.createBpmn()
      })
    },
    // 调整左侧工具栏排版
    adjustPalette() {
      try {
        // 获取 bpmn 设计器实例
        const canvas = this.$refs.canvas
      } catch (e) {
        console.log(e)
      }
    },
    // 下载为SVG格式,done是个函数，调用的时候传入的
    saveSVG(done) {
      // 把传入的done再传给bpmn原型的saveSVG函数调用
      this.bpmnModeler.saveSVG(done)
    },
    downloadBpmn() {
      this.bpmnModeler.saveXML({ format: true }, (err, xml) => {
        if (!err) {
          // 获取文件名
          const name = `${this.getFilename(xml)}.bpmn`
          // 将文件名以及数据交给下载函数
          this.download({ name: name, data: xml })
        }
      })
    },
    openBpmn(file) {
      const reader = new FileReader()
      // 读取File对象中的文本信息，编码格式为UTF-8
      reader.readAsText(file, 'utf-8')
      reader.onload = () => {
        // 读取完毕后将文本信息导入到Bpmn建模器
        this.createNewDiagram(reader.result)
      }
      return false
    },
    getFileByName() {
      return this.bpmnModeler.getDefinitions().rootElements[0].formKey
    },
    getFilename() {
      return this.bpmnModeler.getDefinitions().rootElements[0].name
    },
    getFileId() {
      return this.bpmnModeler.getDefinitions().rootElements[0].id
    },
    download({ name = 'diagram.bpmn', data }) {
      // 这里就获取到了之前设置的隐藏链接
      const downloadLink = this.$refs.downloadLink
      // 把数据转换为URI，下载要用到的
      const encodedData = encodeURIComponent(data)
      if (data) {
        // 将数据给到链接
        downloadLink.href =
          'data:application/bpmn20-xml;charset=UTF-8,' + encodedData
        // 设置文件名
        downloadLink.download = name
        // 触发点击事件开始下载
        downloadLink.click()
      }
    },
    downloadSvg() {
      this.bpmnModeler.saveXML({ format: true }, (err, xml) => {
        if (!err) {
          xml = xml.replace(/camunda/ig, 'activiti')
          // 获取文件名
          const name = `${this.getFilename(xml)}.svg`
          // 从建模器画布中提取svg图形标签
          let context = ''
          const djsGroupAll = this.$refs.canvas.querySelectorAll('.djs-group')
          for (const item of djsGroupAll) {
            context += item.innerHTML
          }
          const viewport = this.$refs.canvas
            .querySelector('.viewport')
            .getBBox()
          // 将标签和数据拼接成一个完整正常的svg图形
          const svg = `
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="${viewport.width}"
          height="${viewport.height}"
          viewBox="${viewport.x} ${viewport.y} ${viewport.width} ${viewport.height}"
          version="1.1"
          >
          ${context}
        </svg>`
          // 将文件名以及数据交给下载函数
          this.download({ name: name, data: svg })
        }
      })
    },
    // 当图发生改变的时候会调用这个函数，这个data就是图的xml
    setEncoded(link, name, data) {
      // 把xml转换为URI，下载要用到的
      const encodedData = encodeURIComponent(data)
      // 获取到图的xml，保存就是把这个xml提交给后台
      this.xmlStr = data
      // 下载图的具体操作,改变a的属性，className令a标签可点击，href令能下载，download是下载的文件的名字
      if (data) {
        link.className = 'active'
        link.href = 'data:application/bpmn20-xml;charset=UTF-8,' + encodedData
        link.download = name
      }
    },
    saveFlow(status) {
      this.bpmnModeler.saveXML({ format: true }, (err, xml) => {
        // 从建模器画布中提取svg图形标签
        let context = ''
        const djsGroupAll = this.$refs.canvas.querySelectorAll('.djs-group')
        for (const item of djsGroupAll) {
          context += item.innerHTML
        }
        const viewport = this.$refs.canvas
          .querySelector('.viewport')
          .getBBox()
        const svg = `
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="${viewport.width}"
          height="${viewport.height}"
          viewBox="${viewport.x} ${viewport.y} ${viewport.width} ${viewport.height}"
          version="1.1"
          >
          ${context}
        </svg>`
        saveData({
          modelStatus: status,
          id: this.id,
          thumbnail: xml,
          name: this.getFilename(),
          svg: svg,
          modelKey: this.getFileId()
        }).then(() => {
          this.$notify({
            title: '成功',
            message: '保存成功！',
            type: 'success',
            duration: 2000
          })
        })
      })
    },
    getRandom(num) {
      return Math.floor((Math.random() + Math.floor(Math.random() * 9 + 1)) * Math.pow(10, num - 1))
    }
  },
  mounted() {
    const canvas = this.$refs.canvas
    // 生成实例
    this.bpmnModeler = new BpmnModeler({
      additionalModules: [
        propertiesProviderModule
      ],
      container: canvas
    })
    if (this.flowId) {
      this.id = this.flowId
      this.fetchData(this.flowId)
    } else {
      this.id = this.getRandom(19)
      this.createNewDiagram(this.bpmnTemplate)
    }
  }
}
</script>

<style lang="scss">
/*左边工具栏以及编辑节点的样式*/
@import "~bpmn-js/dist/assets/diagram-js.css";
@import "~bpmn-js/dist/assets/bpmn-font/css/bpmn.css";
@import "~bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css";
@import "~bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css";
.containers {
  position: absolute;
  background-color: #ffffff;
  width: 100%;
  height: 100%;
  .canvas {
    width: 100%;
    height: 700px;
    background: url("") repeat!important
  }
  .panel {
    position: absolute;
    right: 0;
    top: 50px;
    width: 300px;
  }
  .bjs-powered-by {
    display: none;
  }
  .toolbar {
    position: absolute;
    top: 20px;
    right: 350px;
    a {
      text-decoration: none;
      margin: 5px;
      color: #409eff;
    }
  }
}
</style>
